﻿/* Copyright 2012 Sannel Software, L.L.C.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at

 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Text;

namespace Sannel.Calculate.Nodes
{
	public abstract class BaseNode
	{
		public BaseNode Next
		{
			get;
			protected set;
		}

		public BaseNode Previous
		{
			get;
			protected set;
		}

		public SectionNode Parent
		{
			get;
			// Only BaseNode or SectionNode should set the parent
			internal set;
		}

		/// <summary>
		/// Returns the type of this node.
		/// </summary>
		public abstract NodeType NodeType
		{
			get;
		}

		/// <summary>
		/// When implemented in an inhareted class copys the content of the current node into a new node of that same type.
		/// It does not copy any list pointer. On the new node Next and Previous should be null.
		/// </summary>
		/// <returns></returns>
		public abstract BaseNode Copy();

		/// <summary>
		/// Removes this node from the list by setting Next.Previous to this.Previous and Previous.Next to this.Next
		/// and sets this.Previous and this.Next to null;
		/// </summary>
		public void RemoveFromList()
		{
			if (Next != null)
			{
				Next.Previous = Previous;
			}

			if (Previous != null)
			{
				Previous.Next = Next;
			}

			if (Parent != null)
			{
				Parent.MovePreviousIfLast(this);
				Parent.MoveNextIfFirst(this);

				Parent = null;
			}

			Previous = null;
			Next = null;

			
		}

		/// <summary>
		/// Inserts the node provided in between this node and the next node. If node is already part of a list it will be removed via RemoveFromList()
		/// </summary>
		/// <param name="node">The node to be inserted after this node.</param>
		public void InsertNext(BaseNode node)
		{
			if (node == null)
			{
				throw new ArgumentNullException("node");
			}

			node.RemoveFromList();

			if (Next != null)
			{
				Next.Previous = node;
				node.Next = Next;
			}

			Next = node;
			node.Previous = this;

			if (Parent != null)
			{
				node.Parent = Parent;
				Parent.MoveNextIfLast(this);
			}
		}

		/// <summary>
		/// Inserts the node provided in between this node and the previous node. If node is already part of a list it will be removed via RemoveFromList()
		/// </summary>
		/// <param name="node">The node to be inserted before this node</param>
		public void InsertPrevious(BaseNode node)
		{
			if (node == null)
			{
				throw new ArgumentNullException("node");
			}

			node.RemoveFromList();

			if (Previous != null)
			{
				Previous.Next = node;
				node.Previous = Previous;
			}

			Previous = node;
			node.Next = this;
			
			if (Parent != null)
			{
				node.Parent = Parent;
				Parent.MovePreviousIfFirst(this);
			}
		}

		/// <summary>
		/// Replaces this node with the node passed in. If node is already part of a list it will be removed via RemoveFromList()
		/// </summary>
		/// <param name="node">The node that will replace this node</param>
		public void ReplaceWith(BaseNode node)
		{
			if (node == null)
			{
				throw new ArgumentNullException("node");
			}

			node.RemoveFromList();

			if (Previous != null)
			{
				Previous.Next = node;
				node.Previous = Previous;
			}

			if (Next != null)
			{
				Next.Previous = node;
				node.Next = Next;
			}

			if (Parent != null)
			{
				node.Parent = Parent;
				Parent.ReplaceWithIfFirstOrLast(this, node);
				Parent = null;
			}

			Previous = null;
			Next = null;
		}
	}
}
